#pragma once

#include "my_defs.h"
#include "my_crc.h"
#include "my_queue.h"
#include "my_rbtree.h"
#include "my_string.h"
#include "my_thread_base.h"

typedef struct {
    my_str_t                    key;
    void                        *data;
    int                         weight;
    my_queue_t                  queue;
} my_chash_node_t;


static inline void
my_chash_node_init(my_chash_node_t *node,
    my_str_t *key, void *data, int weight)
{
    assert(key != NULL);
    node->key = *key;
    node->data = data;
    node->weight = weight;
}

typedef struct {
    my_rbtree_node_t            tree_node;
    uint32_t                    crc_key;
    my_chash_node_t             *real_node;
} my_chash_vnode_t;


static inline void
my_chash_vnode_init(my_chash_vnode_t *vnode,
    my_chash_node_t *node, int idx)
{
    char buf[64] = { 0 };
    uint32_t crc1, crc2;

    crc1 = my_crc32_short((const u_char *)node->key.data, (size_t)node->key.len);
    int n = snprintf(buf, 64, "#%d-%u-%d#", idx, crc1, idx);

    my_crc32_init(crc2);
    my_crc32_update(&crc2, (const u_char *)buf, (size_t)n);
    my_crc32_update(&crc2, (const u_char *)node->key.data, (size_t)node->key.len);
    my_crc32_update(&crc2, (const u_char *)buf, (size_t)n);
    my_crc32_final(crc2);

    vnode->crc_key = crc2;
    vnode->real_node = node;
}


static inline int
my_chash_vnode_cmp(my_rbtree_node_t *a, my_rbtree_node_t *b)
{
    my_chash_vnode_t *anode = (my_chash_vnode_t *)a;
    my_chash_vnode_t *bnode = (my_chash_vnode_t *)b;

    if (anode->crc_key == bnode->crc_key) {
        return 0;
    }

    return anode->crc_key > bnode->crc_key ? 1 : -1;
}


typedef struct {
    int                         replace;
    int                         nnode;
    my_queue_t                  head;
    my_rbtree_t                 tree;
    my_rbtree_node_t            sentinel;
    my_chash_node_t             **nodes;
    int64_t                     total_weight;
} my_chash_t;


#define MY_CHASH_DEF_REPLACE    (256)

my_chash_t *my_chash_create(int replace);

void my_chash_add_node(my_chash_t *chash, my_str_t *key, void *data, int weight);

void my_chash_build(my_chash_t *chash);

typedef my_bool_t (*my_chash_node_check_pt) (my_chash_node_t *node);

void *my_chash_get(my_chash_t *chash, my_str_t *key,
    my_chash_node_check_pt checker, my_bool_t must_get);

void my_chash_destroy(my_chash_t *chash);

